#include "HL2Interface.h"

HL2Interfaces g_pInterfaces;

/////////////////////////////////////////////////////
// Hooks

CUserCmd* __stdcall hkGetUserCmd(int seq)
{
	DWORD GetUserCmd = *(DWORD*)((DWORD)g_pInterfaces.g_pInput + 0xC4) + (seq  % 90 << 6);
	CUserCmd* pCmd = (CUserCmd*)GetUserCmd;
	CUserCmd Temp;
	Temp = *pCmd;

	g_pNoSpread.ApplySeedSpread(pCmd);

	g_pBHop.Compute(pCmd);

	return pCmd;
}

void __fastcall hkCreateMove(void* thisptr, int edx, int sequence_number, float input_sample_frametime, bool active) 
{
	typedef void (__thiscall *CreateMove_t) (void*, int sequence_number, float input_sample_frametime, bool active);
	g_pInterfaces.g_pClientHooks->GetMethod<CreateMove_t>(CLIENT_CREATEMOVE)(thisptr, sequence_number, input_sample_frametime, active);

	if(!g_pInterfaces.g_pInput)
		return;

	CVerifiedUserCmd* pSafeCommand = *reinterpret_cast<CVerifiedUserCmd**>((size_t)g_pInterfaces.g_pInput + 0xC8) + (sequence_number % 90);
	CUserCmd* pCmd = g_pInterfaces.g_pInput->GetUserCmd(sequence_number); 

	if(!pCmd)
		return;

	g_pNoHands.Compute();
	g_pNoflash.Compute();
	g_pNoSmoke.Compute();
	g_pCheats.Compute();
	g_pHudRadar.Compute();
	g_pSpeedhack2.Set((GetAsyncKeyState('F') & (1<<15)) != 0);
	g_pNoSpread.ApplyNoRecoil(pCmd, g_pAimbot.Compute(pCmd));
	g_pEasyTrigger.Compute(pCmd);
	g_pAutoPistol.Compute(pCmd);
	g_pKnifebot.Compute(pCmd);

	if(pCmd->buttons & IN_ATTACK)
	{
		g_pSpeedhack2.Disable();
	}

	g_pSpeedhack2.Compute();

	GameUtilities::FixAngle(&pCmd->viewangles);

	g_pEventManager.RegisterSelf();

	pSafeCommand->m_cmd = *pCmd;
	pSafeCommand->m_crc = pSafeCommand->m_cmd.GetChecksum();
}

void __fastcall hkPaintTraverse(void* thisptr, int edx, unsigned int vguiPanel, bool forceRepaint, bool allowForce)
{
	typedef const char* (__thiscall* GetName_t)(void*, unsigned int);
	const char* name = g_pInterfaces.g_pPanelHooks->GetMethod<GetName_t>(PANEL_GETNAME)(thisptr, vguiPanel);

	typedef void (__thiscall *PaintTraverse_t)(void* thisptr, unsigned int vguiPanel, bool forceRepaint, bool allowForce);
	g_pInterfaces.g_pPanelHooks->GetMethod<PaintTraverse_t>(PANEL_PAINTTRAVERSE)(thisptr, vguiPanel, forceRepaint, allowForce);

	if(name[0] == 'M' && name[3] == 'S' && name[9] == 'T' && name[12] == 'P') // [M]at[S]ystem[T]op[P]anel
	{
		// Draw Here
		g_pESP.Init();

		if(!g_pInterfaces.g_pEngine->IsInGame())
			return;

		g_pFont->PrintString(15, 15, 255, 255, 255, 255, FA_Left|FA_CenterH, "TettenHook v1.0.1");

		char TokenStr[1024];
		strcpy(TokenStr, g_pConfigManager.GetActiveFeatureString());
		char* Token = TokenStr;
		int YOffset = 100;
		Token = strtok(TokenStr, "\n");
		while (Token)
		{
			g_pFont->PrintString(15, YOffset, 255, 0, 0, 255, FA_Left|FA_CenterH, "%s", Token);
			YOffset += 20;
			Token = strtok(NULL, "\n");
		}
		//g_pFont->PrintString(15, 100, 255, 0, 0, 255, FA_Left|FA_CenterH, "%s", g_pConfigManager.GetActiveFeatureString());

		g_pESP.Draw();

		g_pCrosshair.Draw();
	}
}

IMaterial* __fastcall hkFindMaterial(void* thisptr, int edx, char const* pMaterialName, const char *pTextureGroupName, bool complain/* = true*/, const char *pComplainPrefix/* = NULL*/)
{
	typedef IMaterial* (__thiscall* FindMaterial_t)(void*, char const*, const char *, bool complain, const char *);
	IMaterial* ret = g_pInterfaces.g_pMaterialHooks->GetMethod<FindMaterial_t>(MATSYS_FINDMATERIAL)(thisptr, pMaterialName, pTextureGroupName, complain, pComplainPrefix);
	g_pCheats.ComputeAsus(ret);
	return ret;
}

/////////////////////////////////////////////////////
// Base Funcs

void HL2Interfaces::Start()
{
	if(WaitForGame())
	{
		LoadInterfaces();
		NetvarManager::PullOffsets();
	}
}

bool HL2Interfaces::WaitForGame()
{
	HANDLE hClient = NULL, hEngine = NULL, hVGUI = NULL, hVGUI2 = NULL, hMatSys = NULL;
	while(!hClient || !hEngine || !hVGUI || !hVGUI2)
	{
		hClient = GetModuleHandle(L"client.dll");
		hEngine = GetModuleHandle(L"engine.dll");
		hVGUI   = GetModuleHandle(L"vguimatsurface.dll");
		hVGUI2	= GetModuleHandle(L"vgui2.dll");
		hMatSys = GetModuleHandle(L"materialsystem.dll");
	}
	return true;
}

void HL2Interfaces::LoadInterfaces()
{
	//////////////////////////////////////////////////////////////////////////

	/*AllocConsole();
	freopen("CONOUT$", "w", stdout);
	freopen("CONOUT$", "w", stderr);
	freopen("CONIN$", "r", stdin);
	SetConsoleTitle(L"OSH-Base Debug");
	system("color 05");
	HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
	_CONSOLE_SCREEN_BUFFER_INFO info;
	system("mode CON: COLS=200");
	GetConsoleScreenBufferInfo(ConsoleHandle,&info);
	SMALL_RECT windowMaxSize = {0, 0, info.dwMaximumWindowSize.X-1, info.dwMaximumWindowSize.Y-1};
	SetConsoleWindowInfo(ConsoleHandle, TRUE, &windowMaxSize);*/
	
	//////////////////////////////////////////////////////////////////////////


	CreateInterfaceFn fnClient = NULL;
	CreateInterfaceFn fnEngine = NULL;
	CreateInterfaceFn fnVGUI   = NULL;
	CreateInterfaceFn fnVGUI2  = NULL;
	CreateInterfaceFn fnMatSys = NULL;

	fnClient = (CreateInterfaceFn)(GetProcAddress(GetModuleHandle(L"client.dll"),		  "CreateInterface"));
	fnEngine = (CreateInterfaceFn)(GetProcAddress(GetModuleHandle(L"engine.dll"),		  "CreateInterface"));
	fnVGUI	 = (CreateInterfaceFn)(GetProcAddress(GetModuleHandle(L"vguimatsurface.dll"), "CreateInterface"));
	fnVGUI2	 = (CreateInterfaceFn)(GetProcAddress(GetModuleHandle(L"vgui2.dll"),		  "CreateInterface"));
	fnMatSys = (CreateInterfaceFn)(GetProcAddress(GetModuleHandle(L"materialsystem.dll"), "CreateInterface"));

	g_pClient		= (IBaseClientDLL*)fnClient("VClient017", NULL);
	g_pEntList		= (IClientEntityList*)fnClient("VClientEntityList003", NULL);
	g_pEngine		= (IVEngineClient*)fnEngine("VEngineClient014", NULL);
	g_pEngineTrace  = (IEngineTrace*)fnEngine("EngineTraceClient003", NULL);
	g_pMaterialSystem = (IMaterialSystem*)fnMatSys("VMaterialSystem080", NULL);
	g_pGameEventManager = (IGameEventManager2*)fnEngine("GAMEEVENTSMANAGER002", NULL);

	void* vPanel	= fnVGUI2("VGUI_Panel009", NULL);
	void* vReplay	= fnEngine("EngineClientReplay001", NULL);

	g_pInput		= (CInput*)*(DWORD*)(FindPattern::Find((DWORD)GetModuleHandle(L"client.dll"), 0x89B000 - 0x100, (BYTE*) InputFindPatternA, InputFindPatternB) + InputPatternOffset);

	Offsets::EstimateAbsVelocity = FindPattern::Find((DWORD)GetModuleHandle(L"client.dll"), 0x89B000 - 0x100, (BYTE*) VelocityOffsetFindPatternA, VelocityOffsetFindPatternB) + VelocityOffsetFindPatternOffset;

	g_pKnifebot.Init();
	g_pNoHands.Init();
	g_pNoSmoke.Init();
	g_pNoflash.Init();
	g_pSpeedhack2.Init();
	g_pCrosshair.Init();
	g_pAimbot.Init();
	g_pNoSpread.Init();
	g_pEasyTrigger.Init();
	g_pCheats.Init();
	g_pBHop.Init();
	g_pAutoPistol.Init();
	g_pHudRadar.Init();
	g_pEventManager.Init();
	
	g_pConfigManager.Load();

	g_pSurface.Init((PDWORD_PTR*)fnVGUI("VGUI_Surface030", NULL));
	g_pFont = Font::BuildFont("Helvetica", 14, 350, FF_OUTLINE|FF_DROPSHADOW);

	if(g_pInput)
	{
		static hook_t InputHook((void*)g_pInput);
		g_pInputHooks = &InputHook;
		InputHook.HookMethod(&hkGetUserCmd, INPUT_GETUSERCMD);
	}

	if(g_pClient)
	{
		static hook_t ClientHook((void*)g_pClient);
		g_pClientHooks = &ClientHook;
		ClientHook.HookMethod(&hkCreateMove, CLIENT_CREATEMOVE);
	}

	if(vPanel)
	{
		static hook_t PanelHook(vPanel);
		g_pPanelHooks = &PanelHook;
		PanelHook.HookMethod(&hkPaintTraverse, PANEL_PAINTTRAVERSE);
	}

	if(g_pMaterialSystem)
	{
		static hook_t MHook(g_pMaterialSystem);
		g_pMaterialHooks = &MHook;
		MHook.HookMethod(&hkFindMaterial, MATSYS_FINDMATERIAL);
	}

	if(vReplay)
	{
		hook_t ReplayHook(vReplay);
		typedef CGlobalVarsBase* (__thiscall* GetGlobalVars_t)(void*);
		g_pGlobals = ReplayHook.GetMethod<GetGlobalVars_t>(REPLAY_GETGLOBALVARS)(vReplay);
	}
}